package com.gitee.wsl.compose.chart.xy.line.area

import androidx.compose.animation.core.AnimationSpec
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathFillType
import com.gitee.wsl.common.ui.draw.style.AreaStyle
import com.gitee.wsl.common.ui.draw.style.LineStyle
import com.gitee.wsl.common.ui.ext.path.lineTo
import com.gitee.wsl.common.ui.ext.path.moveTo
import com.gitee.wsl.compose.chart.KoalaPlotTheme
import com.gitee.wsl.compose.chart.SelectCheck
import com.gitee.wsl.compose.chart.xy.SymbolSlate
import com.gitee.wsl.compose.chart.xy.model.PointEntry
import com.gitee.wsl.compose.chart.xy.XYGraphScope
import com.gitee.wsl.compose.chart.xy.line.area.model.AreaBaseline
import com.gitee.wsl.compose.chart.xy.line.GeneralLinePlot
import com.gitee.wsl.compose.chart.xy.line.LinePlot
import com.gitee.wsl.compose.chart.xy.line.LinePlotSlate


/**
 * An area plot that draws data as points and lines with a filled area to a baseline.
 * @param X The type of the x-axis values
 * @param Y The type of the y-axis values
 * @param data Data series to plot.
 * @param lineStyle Style to use for the line that connects the data points. If null, no line is drawn.
 * @param symbol Composable for the symbol to be shown at each data PointEntry.
 * @param areaStyle Style to use for filling the area between the line and a baseline. If null, no area will be drawn.
 * @param areaBaseline Baseline location for the area. If [areaBaseline] is an [AreaBaseline.ArbitraryLine] then it is
 * recommended that the first and last x-axis values for the baseline match those in the [data] so the
 * left and right area bounds will be vertical.
 * @param modifier Modifier for the plot.
 */
@Composable
 fun <X, Y> XYGraphScope<X, Y>.AreaPlot(
    data: List<PointEntry<X, Y>>,
    areaBaseline: AreaBaseline<X, Y>,
    areaStyle: AreaStyle,
    modifier: Modifier = Modifier,
    lineStyle: LineStyle? = null,
    symbol: SymbolSlate<PointEntry<X, Y>>? = null,
    animationSpec: AnimationSpec<Float> = KoalaPlotTheme.animationSpec,
    selected :Boolean = false
) {
    if (data.isEmpty()) return

    GeneralLinePlot(
        data,
        modifier,
        lineStyle,
        symbol,
        areaStyle,
        areaBaseline,
        animationSpec,
        selected
    ) { points: List<PointEntry<X, Y>>, size: Size ->
        moveTo(scale(points[0], size))
        for (index in 1..points.lastIndex) {
            lineTo(scale(points[index], size))
        }
    }
}

fun <X, Y> XYGraphScope<X, Y>.generateArea(
    areaBaseline: AreaBaseline<X, Y>,
    data: List<PointEntry<X, Y>>,
    mainLinePath: Path,
    size: Size,
    drawConnectorLine: Path.(points: List<PointEntry<X, Y>>, size: Size) -> Unit
): Path {
    return Path().apply {
        fillType = PathFillType.EvenOdd
        when (areaBaseline) {
            is AreaBaseline.ArbitraryLine -> {
                addPath(mainLinePath)

                // right edge of fill area
                lineTo(scale(areaBaseline.values.last(), size))

                // draw baseline
                drawConnectorLine(areaBaseline.values.reversed(), size)

                // draw left edge of fill area
                lineTo(scale(data.first(), size))

                close()
            }

            is AreaBaseline.ConstantLine -> {
                addPath(mainLinePath)

                // right edge
                lineTo(scale(PointEntry(data.last().x, areaBaseline.value), size))

                // baseline
                lineTo(scale(PointEntry(data.first().x, areaBaseline.value), size))

                // left edge
                lineTo(scale(data.first(), size))

                close()
            }
        }
    }
}